package cz.proks.easyhelpdesk.gwt;

import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceHistoryMapper;
import com.google.gwt.regexp.shared.MatchResult;
import com.google.gwt.regexp.shared.RegExp;

import cz.proks.easyhelpdesk.gwt.place.WelcomePlace;
import cz.proks.easyhelpdesk.gwt.place.base.AHelpdeskPlace;

public class HelpdeskPlaceHistoryMapper implements PlaceHistoryMapper {   
    private final RegExp placeholderPattern = RegExp.compile("\\{[^\\}]+\\}");
    private final RegExp optionalRegexCharPattern = RegExp.compile(".\\?", "g");
    
    private final Set<AHelpdeskPlace> helpdeskPlaces = new HashSet<AHelpdeskPlace>();
    private final Map<AHelpdeskPlace, RegExp> placesPatterns = new HashMap<AHelpdeskPlace, RegExp>();      
    
    public HelpdeskPlaceHistoryMapper() {       
    }
            
    public void addPlace(AHelpdeskPlace helpdeskPlace) {
        helpdeskPlaces.add(helpdeskPlace);
        placesPatterns.put(helpdeskPlace, compileForMatch(helpdeskPlace.getPattern()));
    }
    
    @Override
    public Place getPlace(String token) {
        for (AHelpdeskPlace place : helpdeskPlaces) {
            RegExp placePattern = placesPatterns.get(place);
            
            if (matchesString(placePattern, token)) {
                List<String> placesValues = getPlaceValues(place.getPattern(), token);
                place.initFromList(placesValues);
                return place;
            }
        }               
        
        return new WelcomePlace();
    }

    @Override
    public String getToken(Place place) {
        if (!(place instanceof AHelpdeskPlace))
            return "";
        
        AHelpdeskPlace helpdeskPlace = (AHelpdeskPlace) place;
        String pattern = helpdeskPlace.getPattern();
        String token = getPlaceToken(pattern, helpdeskPlace.getPlaceValues());
        return token;
    }
        
    private RegExp compileForMatch(String pattern) {
        String patternForMatch = pattern.replaceAll("\\{[^\\}]+\\}", "\\\\w+"); 
        return RegExp.compile(patternForMatch);
    }
    
    private List<String> getPlaceValues(String pattern, String token) {
        List<String> values = new LinkedList<String>();
        
        String[] patternSplit = pattern.split("/");
        String[] tokenSplit = token.split("/");
        
        for (int i = 0; i < patternSplit.length; i++) {
            String patternS = patternSplit[i];
            
            if (matchesString(placeholderPattern, patternS) && i < tokenSplit.length)
                values.add(tokenSplit[i]);
        }                
        
        return values;        
    }
    
    private String getPlaceToken(String pattern, List<String> placeholderValues) {
        if (placeholderValues == null || placeholderValues.isEmpty())
            return pattern;
        
        pattern = optionalRegexCharPattern.replace(pattern, "");
        
        for (String value : placeholderValues)
            pattern = placeholderPattern.replace(pattern, value);
        
        return pattern;
    }
    
    private boolean matchesString(RegExp pattern, String input) {
        MatchResult matcher = pattern.exec(input);
        return matcher != null && matcher.getGroupCount() == 1 && matcher.getGroup(0).length() == input.length();
    }
}
